"""
需求：实现基于mysql数据库构建问答系统中的mysql_qa模块的相关操作，包括创建表、从 CSV 文件插入数据、查询问题和答案，以及安全关闭连接等操作
实现思路：
    1：创建数据库连接和游标
    2：实现创建表的方法
    3：实现从 CSV 文件插入数据的方法
    4：实现查询问题的方法
    5：实现根据问题查找对应的答案
    6：实现安全关闭连接的方法
"""

#导包
import pymysql
import pandas as pd
from base.config import get_config
from base.logger import get_logger

# 创建mysql操作的客户端工具类
class MysqlClient:
    def __init__(self):
        """
        1：创建数据库连接和游标

        功能：
        - 建立与MySQL数据库的连接
        - 创建数据库游标对象
        - 初始化配置信息和日志记录器

        异常处理：
        - 捕获数据库连接异常并记录错误日志
        - 连接失败时重新抛出异常

        所需配置：
        - MYSQL_HOST: 数据库主机地址
        - MYSQL_PORT: 数据库端口号
        - MYSQL_USER: 数据库用户名
        - MYSQL_PASSWORD: 数据库密码
        - MYSQL_DATABASE: 数据库名称
        """
        # 创建数据库连接和游标
        self.config = get_config()
        self.logger = get_logger()
        try:
            # 建立数据库连接并创建游标对象
            self.conn = pymysql.connect(
                host=self.config.MYSQL_HOST,
                port=self.config.MYSQL_PORT,
                user=self.config.MYSQL_USER,
                password=self.config.MYSQL_PASSWORD,
                database=self.config.MYSQL_DATABASE
            )
            self.cursor = self.conn.cursor()
            self.logger.info("创建数据库连接和游标成功")
        except Exception as e:
            self.logger.error(f"创建数据库连接和游标失败：{e}")
            raise

    def create_table(self):
        """
        2：实现创建表的方法

        功能：
        - 执行SQL语句创建数据库表
        - 提交事务到数据库

        参数：
        - sql: 包含CREATE TABLE语句的字符串

        异常处理：
        - 捕获SQL执行异常并记录错误日志
        - 回滚事务并重新抛出异常

        所需配置：
        - 数据库连接已初始化
        """
        create_table_sql = """
            CREATE TABLE IF NOT EXISTS `jpkb` (
                `id` INT AUTO_INCREMENT PRIMARY KEY,
                `subject_name` VARCHAR(20),
                `question` VARCHAR(1000),
                `answer` VARCHAR(1000)
            );
        """
        try:
            self.cursor.execute(create_table_sql)
            self.conn.commit()
            self.logger.info("创建数据库表成功")
        except Exception as e:
            self.logger.error(f"创建数据库表失败：{e}")
            self.conn.rollback()
            raise

    def insert_data(self, csv_file):
        """
        3：实现从 CSV 文件插入数据

        功能：
        - 从CSV文件中读取数据并插入数据库表
        - 批量插入数据，提高效率

        参数：
        - csv_file: CSV文件路径

        异常处理：
        - 捕获SQL执行异常并记录错误日志
        - 回滚事务并重新抛出异常
        """
        try:
            # 从CSV文件中读取数据
            df = pd.read_csv(csv_file)
            # 遍历每一行数据，将数据插入到数据库表中
            for _, row in df.iterrows():
                # 学科名称
                subject_name = row["学科名称"]
                # 问题
                question = row["问题"]
                # 答案
                answer = row["答案"]
                # 构造sql插入语句，将数据写入到jpkb表中，包含学科名称、 问题和答案，确保数据插入成功
                # 其中%s表示占位符，实际插入的数据会替换成对应的值，防止SQL注入攻击
                insert_sql = """
                             INSERT INTO `jpkb` (`subject_name`, `question`, `answer`)
                             VALUES (%s, %s, %s); \
                             """
                self.cursor.execute(insert_sql, (subject_name, question, answer))
            self.conn.commit()
            self.logger.info("从CSV文件插入数据成功")
        except Exception as e:
            self.logger.error(f"读取CSV文件失败：{e}")
            self.conn.rollback()
            raise

    def fetch_all_questions(self):
        """
        4：实现查询问题的方法
        功能：
        - 从数据库表中查询所有问题
        返回：
        - questions: 包含所有问题的列表
        异常处理：
        - 捕获SQL执行异常并记录错误日志
        - 重新抛出异常
        """
        try:
            # 构造sql查询语句，查询jpkb表中的所有问题
            query_sql = """
                        SELECT `question` FROM `jpkb`
                        """
            self.cursor.execute(query_sql)
            questions = self.cursor.fetchall()
            self.logger.info("查询所有问题成功")
            return questions
        except Exception as e:
            self.logger.error(f"查询所有问题失败：{e}")
            return []

    def fetch_answer(self, question):
        """
        5：实现根据问题查找对应的答案
        功能：
        - 从数据库表中根据问题查询对应的答案
        参数：
        - question: 问题字符串
        返回：
        - answer: 对应的答案字符串
        异常处理：
        - 捕获SQL执行异常并记录错误日志
        - 重新抛出异常
        """
        try:
            # 构造sql查询语句，根据问题查询对应的答案
            query_sql = """
                        SELECT `answer` FROM `jpkb` WHERE `question` = %s
                        """
            self.cursor.execute(query_sql, (question))
            # 获取查询结果, 如果查询结果不为空，则返回对应的答案字符串，否则返回None
            # self.cursor.fetchone()返回的是一个元组，元组中包含查询结果的第一行数据
            # 如果查询结果为空，则返回None
            # 如果查询结果不为空，则返回对应的答案字符串
            answer = self.cursor.fetchone()
            self.logger.info("根据问题查询答案成功")
            return answer[0] if answer else None
        except Exception as e:
            self.logger.error(f"根据问题查询答案失败：{e}")
            return None

    def close(self):
        """
        6：实现关闭数据库连接的方法
        功能：
        - 关闭数据库连接和游标
        异常处理：
        - 捕获异常并记录错误日志
        """
        try:
            if self.cursor:
                self.cursor.close()
            if self.conn:
                self.conn.close()
            self.logger.info("关闭数据库连接和游标成功")
        except Exception as e:
            self.logger.error(f"关闭数据库连接和游标失败：{e}")

if __name__ == '__main__':
    mysql_client = MysqlClient()
    mysql_client.create_table()
    mysql_client.insert_data("F:\\code\\integrated_qa_system\\mysql_qa\\data\\JP学科知识问答.csv")
    result = mysql_client.fetch_all_questions()
    print(result)
    # result = mysql_client.fetch_answer("关联子查询的执行顺序是什么")
    # print(result)
    # mysql_client.close()
